package org.easy.eao.spring;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.easy.eao.Action;
import org.easy.eao.ActionBuilder;
import org.easy.eao.EaoBuilder;
import org.easy.eao.EaoHandler;
import org.easy.eao.executer.Executer;
import org.easy.eao.executer.ExecuterBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * EAO 工厂接口的 Spring 实现类
 * 
 * @author Frank
 */
public class SpringEaoBuilder implements EaoBuilder, BeanClassLoaderAware, BeanFactoryAware, InitializingBean {

	private ClassLoader classLoader;
	private ConfigurableListableBeanFactory beanFactory;
	private ActionBuilder actionBuilder;
	private ExecuterBuilder executerBuilder = new ExecuterBuilder();

	@Override
	public void afterPropertiesSet() throws Exception {
		actionBuilder = (ActionBuilder) beanFactory.createBean(SpringActionBuilder.class);
	}

	@Override
	public Object builder(Class<?> clazz, Set<Class<Action<?>>> actionsClz) {
		Map<Method, Executer> map = new HashMap<Method, Executer>();
		for (Method method : clazz.getMethods()) {
			List<Action<?>> actions = actionBuilder.buildActions(clazz, method, actionsClz);
			Executer executer = executerBuilder.builder(clazz, method, actions);
			map.put(method, executer);
		}

		EaoHandler handler = new EaoHandler();
		handler.setExecuters(map);
		return Proxy.newProxyInstance(classLoader, new Class<?>[] { clazz }, handler);
	}

	// Setter ...

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
	}

}
